package com.sk.bilibili.apiMapper.component;

import com.sk.bilibili.apiMapper.bean.FieldInfo;
import com.sk.bilibili.apiMapper.interfaces.StringConverter;
import lombok.SneakyThrows;
import org.json.JSONArray;
import org.json.JSONObject;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author 邵康
 * @date 2021/7/11 10:07
 */
public class JsonHandler {

    private List<StringConverter> converters;
    private FieldInfoCache fieldInfoCache;
    private BaseDataHandler baseDataHandler;
    private Pattern ARRAY_INDEX_PATTERN = Pattern.compile("(.*)\\[(\\d+)]");

    public JsonHandler() {
        converters = new ArrayList<>();
        fieldInfoCache = new FieldInfoCache();
        baseDataHandler = new BaseDataHandler();
    }

    public void addStringConverter(StringConverter stringConverter) {
        converters.add(stringConverter);
    }

    public void init() {
        converters.sort(Comparator.comparingInt(StringConverter::order));
        fieldInfoCache.setConverters(converters);
    }

    public Object handleJson(String json, Class clazz, String path) {
        if (path.equals("")) {
            if (clazz.isArray()) {
                return handleJSONArray(new JSONArray(json), clazz.getComponentType());
            } else {
                return handleJSONObject(new JSONObject(json), clazz);
            }
        } else {
            JSONObject object = new JSONObject(json);
            String[] split = path.split("\\.");
            object = movePath(object, split);
            if (clazz.isArray()) {
                return handleJSONArray(object.getJSONArray(split[split.length - 1]), clazz.getComponentType());
            } else {
                Object res = baseDataHandler.handle(object, split[split.length - 1], clazz);
                if (res != null) return res;
                JSONObject target = movePath(object,split[split.length - 1]);
                return handleJSONObject(target, clazz);
            }
        }
    }

    /**
     * 移动到指定位置
     */
    private JSONObject movePath(JSONObject object, String[] split) {
        for (int i = 0; i < split.length - 1; i++) {
            object = movePath(object, split[i]);
        }
        return object;
    }

    private JSONObject movePath(JSONObject object, String path) {
        Matcher matcher = ARRAY_INDEX_PATTERN.matcher(path);
        if (matcher.find()) {//判断是否为数组
            return object.getJSONArray(matcher.group(1))
                    .getJSONObject(Integer.parseInt(matcher.group(2)));
        } else {
            return object.getJSONObject(path);
        }
    }

    private Object handleJSONArray(JSONArray array, Class clazz) {
        Object res = Array.newInstance(clazz, array.length());
        for (int i = 0; i < array.length(); i++) {
            Array.set(res, i, handleJSONObject(array.getJSONObject(i), clazz));
        }
        return res;
    }

    @SneakyThrows
    private Object handleJSONObject(JSONObject object, Class clazz) {
        Object res = clazz.newInstance();
        List<FieldInfo> fieldInfos = fieldInfoCache.getFieldInfo(clazz);
        for (FieldInfo fieldInfo : fieldInfos) {
            Object value;
            JSONObject temp = fieldInfo.movePath(object);
            String lastPath = fieldInfo.getLastPath();
            if (fieldInfo.isCollection()) {
                if (fieldInfo.isArray()) {
                    value = handleJSONArray(temp.getJSONArray(lastPath), fieldInfo.getSonClass());
                } else {
                    value = handleJSONObject(temp.getJSONObject(lastPath), fieldInfo.getClazz());
                }
            } else {
                String src = temp.get(lastPath).toString();
                value = fieldInfo.getConverter().converter(src);
            }
            fieldInfo.setValue(res, value);
        }
        return res;
    }

}
